package com.kexilo.system.controller;

import com.kexilo.core.common.annotation.Debounce;
import com.kexilo.core.common.annotation.Idempotent;
import com.kexilo.core.common.annotation.Log;
import com.kexilo.core.common.core.page.TableDataInfo;
import com.kexilo.core.common.core.web.BaseController;
import com.kexilo.core.common.core.web.domain.R;
import com.kexilo.core.common.enums.BusinessType;
import com.kexilo.core.common.utils.SecurityUtils;
import com.kexilo.core.common.utils.StringUtils;
import com.kexilo.core.role.domain.SysRole;
import com.kexilo.core.role.domain.SysUserRole;
import com.kexilo.core.user.domain.SysUser;
import com.kexilo.system.system.service.ISysMenuService;
import com.kexilo.system.user.service.ISysRoleService;
import com.kexilo.system.user.service.ISysUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * 角色信息
 * 
 * @author Kexilo
 */
@RestController
@RequestMapping("/system/role")
@Tag(name = "角色管理", description = "角色信息管理相关接口")
public class SysRoleController extends BaseController {

    private static final Logger log = LoggerFactory.getLogger(SysRoleController.class);
    
    @Autowired
    private ISysRoleService roleService;
    
    @Autowired
    private ISysUserService userService;
    
    @Autowired
    private ISysMenuService menuService;
    
    /**
     * 获取角色列表
     */
    @PreAuthorize("@ss.hasPermi('system:role:list')")
    @GetMapping("/list")
    @Operation(summary = "获取角色列表", description = "分页获取角色列表信息")
    @ApiResponses({
        @ApiResponse(responseCode = "200", description = "获取成功"),
        @ApiResponse(responseCode = "403", description = "权限不足")
    })
    public TableDataInfo list(SysRole role) {
        startPage();
        List<SysRole> list = roleService.selectRoleList(role);
        return getDataTable(list);
    }
    
    /**
     * 导出角色列表
     */
    @PreAuthorize("@ss.hasPermi('system:role:export')")
    @Log(title = "角色管理", businessType = BusinessType.EXPORT)
    @Debounce(interval = 10, message = "导出操作过于频繁，请稍后再试")
    @PostMapping("/export")
    @Operation(summary = "导出角色列表", description = "导出角色列表数据")
    public R<Void> export(SysRole role) {
        List<SysRole> list = roleService.selectRoleList(role);
        // TODO: 实现导出逻辑
        return success("导出成功");
    }
    
    /**
     * 根据角色编号获取详细信息
     */
    @PreAuthorize("@ss.hasPermi('system:role:query')")
    @GetMapping(value = "/{roleId}")
    @Operation(summary = "获取角色详情", description = "根据角色ID获取角色详细信息")
    public R<SysRole> getInfo(@Parameter(description = "角色ID") @PathVariable Long roleId) {
        roleService.checkRoleDataScope(roleId);
        SysRole role = roleService.selectRoleById(roleId);
        return success(role);
    }
    
    /**
     * 新增角色
     */
    @PreAuthorize("@ss.hasPermi('system:role:add')")
    @Log(title = "角色管理", businessType = BusinessType.INSERT)
    @Debounce(strategy = Debounce.Strategy.REQUEST_PARAMS, interval = 5, message = "请勿重复提交角色信息")
    @Idempotent(strategy = Idempotent.Strategy.REQUEST_PARAMS, key = "#role.roleName", timeout = 5, message = "该角色名正在处理中，请稍后再试")
    @PostMapping
    @Operation(summary = "新增角色", description = "新增角色信息")
    public R<Void> add(@Validated @RequestBody SysRole role) {
        if (!roleService.checkRoleNameUnique(role)) {
            return error("新增角色'" + role.getRoleName() + "'失败，角色名称已存在");
        }
        else if (!roleService.checkRoleKeyUnique(role)) {
            return error("新增角色'" + role.getRoleName() + "'失败，角色权限已存在");
        }
        role.setCreateBy(SecurityUtils.getUsername());
        return toAjax(roleService.insertRole(role));
    }
    
    /**
     * 修改保存角色
     */
    @PreAuthorize("@ss.hasPermi('system:role:edit')")
    @Log(title = "角色管理", businessType = BusinessType.UPDATE)
    @Debounce(strategy = Debounce.Strategy.REQUEST_PARAMS, interval = 3, message = "请勿频繁修改角色信息")
    @Idempotent(strategy = Idempotent.Strategy.REQUEST_PARAMS, key = "#role.roleId", timeout = 3, message = "角色信息正在更新中，请稍后再试")
    @PutMapping
    @Operation(summary = "修改角色", description = "修改角色信息")
    public R<Void> edit(@Validated @RequestBody SysRole role) {
        roleService.checkRoleAllowed(role);
        roleService.checkRoleDataScope(role.getRoleId());
        if (!roleService.checkRoleNameUnique(role)) {
            return error("修改角色'" + role.getRoleName() + "'失败，角色名称已存在");
        }
        else if (!roleService.checkRoleKeyUnique(role)) {
            return error("修改角色'" + role.getRoleName() + "'失败，角色权限已存在");
        }
        role.setUpdateBy(SecurityUtils.getUsername());
        
        if (roleService.updateRole(role) > 0) {
            // 更新缓存用户权限
            // TODO: 实现权限缓存更新
            return success();
        }
        return error("修改角色'" + role.getRoleName() + "'失败，请联系管理员");
    }
    
    /**
     * 修改保存数据权限
     */
    @PreAuthorize("@ss.hasPermi('system:role:edit')")
    @Log(title = "角色管理", businessType = BusinessType.UPDATE)
    @Debounce(strategy = Debounce.Strategy.REQUEST_PARAMS, interval = 5, message = "数据权限修改过于频繁，请稍后再试")
    @Idempotent(strategy = Idempotent.Strategy.REQUEST_PARAMS, key = "#role.roleId", timeout = 3, message = "数据权限正在修改中，请稍后再试")
    @PutMapping("/dataScope")
    @Operation(summary = "修改数据权限", description = "修改角色数据权限信息")
    public R<Void> dataScope(@RequestBody SysRole role) {
        roleService.checkRoleAllowed(role);
        roleService.checkRoleDataScope(role.getRoleId());
        role.setUpdateBy(SecurityUtils.getUsername());
        
        if (roleService.authDataScope(role) > 0) {
            // 更新缓存用户权限
            // TODO: 实现权限缓存更新
            return success();
        }
        return error("修改数据权限失败，请联系管理员");
    }
    
    /**
     * 状态修改
     */
    @PreAuthorize("@ss.hasPermi('system:role:edit')")
    @Log(title = "角色管理", businessType = BusinessType.UPDATE)
    @Debounce(strategy = Debounce.Strategy.REQUEST_PARAMS, interval = 3, message = "状态修改过于频繁，请稍后再试")
    @Idempotent(strategy = Idempotent.Strategy.REQUEST_PARAMS, key = "#role.roleId", timeout = 3, message = "角色状态正在修改中，请稍后再试")
    @PutMapping("/changeStatus")
    @Operation(summary = "修改角色状态", description = "启用/停用角色")
    public R<Void> changeStatus(@RequestBody SysRole role) {
        roleService.checkRoleAllowed(role);
        roleService.checkRoleDataScope(role.getRoleId());
        role.setUpdateBy(SecurityUtils.getUsername());
        return toAjax(roleService.updateRoleStatus(role));
    }
    
    /**
     * 删除角色
     */
    @PreAuthorize("@ss.hasPermi('system:role:remove')")
    @Log(title = "角色管理", businessType = BusinessType.DELETE)
    @Debounce(strategy = Debounce.Strategy.USER_METHOD, interval = 5, message = "删除操作过于频繁，请稍后再试")
    @Idempotent(strategy = Idempotent.Strategy.REQUEST_PARAMS, timeout = 5, delKey = true, message = "删除操作正在进行中，请勿重复操作")
    @DeleteMapping("/{roleIds}")
    @Operation(summary = "删除角色", description = "批量删除角色")
    public R<Void> remove(@Parameter(description = "角色ID数组") @PathVariable Long[] roleIds) {
        return toAjax(roleService.deleteRoleByIds(roleIds));
    }
    
    /**
     * 获取角色选择框列表
     */
    @PreAuthorize("@ss.hasPermi('system:role:query')")
    @GetMapping("/optionselect")
    @Operation(summary = "获取角色选择框列表", description = "获取角色下拉选择列表")
    public R<List<SysRole>> optionselect() {
        return success(roleService.selectRoleAll());
    }
    
    /**
     * 查询已分配用户角色列表
     */
    @PreAuthorize("@ss.hasPermi('system:role:list')")
    @GetMapping("/authUser/allocatedList")
    @Operation(summary = "查询已分配用户角色列表", description = "获取已分配指定角色的用户列表")
    public TableDataInfo allocatedList(SysUser user) {
        startPage();
        List<SysUser> list = userService.selectAllocatedList(user);
        return getDataTable(list);
    }
    
    /**
     * 查询未分配用户角色列表
     */
    @PreAuthorize("@ss.hasPermi('system:role:list')")
    @GetMapping("/authUser/unallocatedList")
    @Operation(summary = "查询未分配用户角色列表", description = "获取未分配指定角色的用户列表")
    public TableDataInfo unallocatedList(SysUser user) {
        startPage();
        List<SysUser> list = userService.selectUnallocatedList(user);
        return getDataTable(list);
    }
    
    /**
     * 取消授权用户
     */
    @PreAuthorize("@ss.hasPermi('system:role:edit')")
    @Log(title = "角色管理", businessType = BusinessType.GRANT)
    @Debounce(strategy = Debounce.Strategy.REQUEST_PARAMS, interval = 3, message = "授权操作过于频繁，请稍后再试")
    @PutMapping("/authUser/cancel")
    @Operation(summary = "取消授权用户", description = "取消用户角色授权")
    public R<Void> cancelAuthUser(@RequestBody SysUserRole userRole) {
        return toAjax(roleService.deleteAuthUser(userRole));
    }
    
    /**
     * 批量取消授权用户
     */
    @PreAuthorize("@ss.hasPermi('system:role:edit')")
    @Log(title = "角色管理", businessType = BusinessType.GRANT)
    @Debounce(strategy = Debounce.Strategy.REQUEST_PARAMS, interval = 5, message = "批量授权操作过于频繁，请稍后再试")
    @Idempotent(strategy = Idempotent.Strategy.REQUEST_PARAMS, key = "#roleId", timeout = 3, message = "批量授权操作正在进行中，请稍后再试")
    @PutMapping("/authUser/cancelAll")
    @Operation(summary = "批量取消授权用户", description = "批量取消用户角色授权")
    public R<Void> cancelAuthUserAll(Long roleId, Long[] userIds) {
        return toAjax(roleService.deleteAuthUsers(roleId, userIds));
    }
    
    /**
     * 批量选择用户授权
     */
    @PreAuthorize("@ss.hasPermi('system:role:edit')")
    @Log(title = "角色管理", businessType = BusinessType.GRANT)
    @Debounce(strategy = Debounce.Strategy.REQUEST_PARAMS, interval = 5, message = "批量授权操作过于频繁，请稍后再试")
    @Idempotent(strategy = Idempotent.Strategy.REQUEST_PARAMS, key = "#roleId", timeout = 3, message = "批量授权操作正在进行中，请稍后再试")
    @PutMapping("/authUser/selectAll")
    @Operation(summary = "批量选择用户授权", description = "批量为用户分配角色")
    public R<Void> selectAuthUserAll(Long roleId, Long[] userIds) {
        roleService.checkRoleDataScope(roleId);
        return toAjax(roleService.insertAuthUsers(roleId, userIds));
    }
    
    /**
     * 获取对应角色部门树列表
     */
    @PreAuthorize("@ss.hasPermi('system:role:query')")
    @GetMapping(value = "/deptTree/{roleId}")
    @Operation(summary = "获取角色部门树", description = "获取角色对应的部门树结构")
    public R<Object> deptTree(@Parameter(description = "角色ID") @PathVariable("roleId") Long roleId) {
        // TODO: 实现部门树获取逻辑
        return R.success("获取成功");
    }
}
